From 592a68575148985edbc76709085da404846ce444 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Florian=20M=C3=BCllner?= Date: Thu, 27 Nov 2025 22:47:46 +0100 Subject: [PATCH] layout: Use promise to ensure primary monitor Both loading the system background and setting up the startup animation depends on having a primary monitor, so we wait for the monitor to appear if necessary. Currently this is done differently in each case, once by having a hook to recall a method when the monitor appears, and once by re-running an idle handler. Replace this with an async `_ensurePrimaryMonitor()` method that we can use to await the primary monitor where needed. Part-of: --- js/ui/layout.js | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/js/ui/layout.js b/js/ui/layout.js index c5e0b8e51..170a5d496 100644 --- a/js/ui/layout.js +++ b/js/ui/layout.js @@ -201,6 +201,7 @@ export const LayoutManager = GObject.registerClass({ this._rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL; this.monitors = []; this.primaryMonitor = null; + this._primaryMonitorReadyResolver = null; this.primaryIndex = -1; this.hotCorners = []; @@ -214,7 +215,6 @@ export const LayoutManager = GObject.registerClass({ this._topActors = []; this._isPopupWindowVisible = false; this._startingUp = true; - this._pendingLoadBackground = false; // Set up stage hierarchy to group all UI actors under one container. this.uiGroup = new UiActor({name: 'uiGroup'}); @@ -355,7 +355,7 @@ export const LayoutManager = GObject.registerClass({ init() { Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); - this._loadBackground(); + this._loadBackground().catch(logError); } showOverview() { @@ -379,6 +379,15 @@ export const LayoutManager = GObject.registerClass({ this._queueUpdateRegions(); } + async _ensurePrimaryMonitor() { + if (this.primaryMonitor) + return; + + const {promise, resolve} = Promise.withResolvers(); + this._primaryMonitorReadyResolver = resolve; + await promise; + } + _updateMonitors() { const display = global.display; @@ -410,10 +419,7 @@ export const LayoutManager = GObject.registerClass({ this.primaryMonitor = this.monitors[this.primaryIndex]; this.bottomMonitor = this.monitors[this.bottomIndex]; - if (this._pendingLoadBackground) { - this._loadBackground(); - this._pendingLoadBackground = false; - } + this._primaryMonitorReadyResolver?.call(); } else { this.primaryMonitor = null; this.bottomMonitor = null; @@ -658,11 +664,9 @@ export const LayoutManager = GObject.registerClass({ return this._keyboardIndex; } - _loadBackground() { - if (!this.primaryMonitor) { - this._pendingLoadBackground = true; - return; - } + async _loadBackground() { + await this._ensurePrimaryMonitor(); + this._systemBackground = new Background.SystemBackground(); this._systemBackground.hide(); @@ -684,14 +688,10 @@ export const LayoutManager = GObject.registerClass({ // This helps to prevent us from running the animation // when the system is bogged down const id = GLib.idle_add(GLib.PRIORITY_LOW, () => { - if (this.primaryMonitor) { - this._systemBackground.show(); - global.stage.show(); - this._prepareStartupAnimation().catch(logError); - return GLib.SOURCE_REMOVE; - } else { - return GLib.SOURCE_CONTINUE; - } + this._systemBackground.show(); + global.stage.show(); + this._prepareStartupAnimation().catch(logError); + return GLib.SOURCE_REMOVE; }); GLib.Source.set_name_by_id(id, '[gnome-shell] Startup Animation'); }); @@ -713,6 +713,8 @@ export const LayoutManager = GObject.registerClass({ // of the screen. async _prepareStartupAnimation() { + await this._ensurePrimaryMonitor(); + // During the initial transition, add a simple actor to block all events, // so they don't get delivered to X11 windows that have been transformed. this._coverPane = new Clutter.Actor({ -- 2.39.5